package com.zxy.study.ui.widget;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.ColorRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import androidx.core.content.ContextCompat;
import androidx.core.content.res.ResourcesCompat;

import com.zxy.study.R;
import com.zxy.study.utils.DimensUtil;


/**
 * @author : Shonn.Zhang
 * @email : shonn.zhang@mart.blue
 * @time : 2020/9/4 20:34
 * @desc : 通用倒计时控件,目前适用于 "00:00:00" 格式的时分秒的位数各自为两位
 */
public class BlueCountDownView extends View {

    private Paint mPaint;

    //字体
    private int mTextColor;
    private int mTextSize;
    private Typeface mFontType;

    //字体的baseline值
    private int mBaseLine;
    //字体左侧偏移量，为了居中显示
    private int mTextLeftOffset;
    private int mHourTextLeftOffset;

    //字体背景色
    private Drawable mTextBg;
    private int mBgMinWidth;
    private int mBgMinHeight;
    private int mBgWidth;
    private int mBgHeight;
    private int mHourBgWidth;


    //背景的top值
    private int mBgTop;

    //冒号属性
    private int mColonColor;
    private int mColonSize;
    private int mColonPadding;
    //冒号top值
    private int mColonTop;

    private String mHourText = "00";
    private String mMinuteText = "00";
    private String mSecondText = "00";

    //剩余倒计时时间
    private int mCurCountTime;

    /**
     * 是否需要绘制
     * 用于控制当View可见性发生变化时，是否执行绘制操作
     */
    private boolean isDrawText = true;

    private OnCountDownListener mOnCountDownListener;
    private static Handler mHandler = new Handler(Looper.getMainLooper());


    public BlueCountDownView(Context context) {
        this(context, null);
    }

    public BlueCountDownView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, -1);
    }

    public BlueCountDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(context.obtainStyledAttributes(attrs, R.styleable.BlueCountDownView, defStyleAttr, -1));
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public BlueCountDownView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context.obtainStyledAttributes(attrs, R.styleable.BlueCountDownView, defStyleAttr, defStyleRes));
    }

    private void init(TypedArray ta) {
        mTextColor = ta.getColor(R.styleable.BlueCountDownView_time_text_color, Color.WHITE);
        mTextSize = ta.getDimensionPixelOffset(R.styleable.BlueCountDownView_time_text_size, DimensUtil.dp2px(getContext(), 14));
        mTextBg = ta.getDrawable(R.styleable.BlueCountDownView_time_text_bg);
        mColonColor = ta.getColor(R.styleable.BlueCountDownView_time_colon_color, Color.BLACK);
        mColonSize = ta.getDimensionPixelSize(R.styleable.BlueCountDownView_time_colon_size, DimensUtil.dp2px(getContext(), 2));
        mColonPadding = ta.getDimensionPixelSize(R.styleable.BlueCountDownView_time_colon_padding, DimensUtil.dp2px(getContext(), 3));

        mBgMinWidth = ta.getDimensionPixelSize(R.styleable.BlueCountDownView_time_text_bg_minWidth, DimensUtil.dp2px(getContext(), 16));
        mBgMinHeight = ta.getDimensionPixelSize(R.styleable.BlueCountDownView_time_text_bg_minHeight, DimensUtil.dp2px(getContext(), 16));
        int fontResId = ta.getResourceId(R.styleable.BlueCountDownView_time_font_style, R.font.roboto_regular);
        mFontType = ResourcesCompat.getFont(getContext(), fontResId);

        ta.recycle();

        mPaint = new Paint();
        mPaint.setColor(mTextColor);
        mPaint.setTextSize(mTextSize);
        mPaint.setAntiAlias(true);
        if (mFontType != null) {
            mPaint.setTypeface(mFontType);
        }

        Rect textRect = new Rect();
        mPaint.getTextBounds(mMinuteText, 0, mMinuteText.length(), textRect);

        mBgWidth = Math.max(textRect.width() + DimensUtil.dp2px(getContext(), 4), mBgMinWidth);
        mBgHeight = (int) Math.max(mPaint.descent() - mPaint.ascent(), mBgMinHeight);

        mTextLeftOffset = (int) ((mBgWidth - textRect.width() - 0.5f) / 2);
        mHourTextLeftOffset = mTextLeftOffset;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);

        final Rect rect = new Rect();
        mPaint.getTextBounds(mHourText, 0, mHourText.length(), rect);
        mHourBgWidth = rect.width() + DimensUtil.dp2px(getContext(), 4);
        if(mHourBgWidth > mBgWidth){
            mHourTextLeftOffset = (int) ((mHourBgWidth -rect.width()- 0.5f)/2);
        }else {
            mHourBgWidth = mBgWidth;
            mHourTextLeftOffset = mTextLeftOffset;
        }

        int measureWidth = (int) (mHourBgWidth + mBgWidth * 2 + 2 * (mColonSize + 2 * mColonPadding));
        int measureHeight = mBgHeight;

        if (widthMode == MeasureSpec.EXACTLY) {
            measureWidth = Math.max(measureWidth, MeasureSpec.getSize(widthMeasureSpec));
        }
        if (heightMode == MeasureSpec.EXACTLY) {
            measureHeight = Math.max(measureHeight, MeasureSpec.getSize(heightMeasureSpec));
        }

        mBgTop = (measureHeight - mBgHeight) / 2;
        if (mBgTop < 0) {
            mBgTop = 0;
        }
        mBaseLine = (int) (mBgTop + (mBgHeight - mPaint.descent() + mPaint.ascent()) / 2 - mPaint.ascent());
        mColonTop = mBgTop + (mBgHeight - 2 * mColonSize - mColonPadding) / 2;

        setMeasuredDimension(MeasureSpec.makeMeasureSpec(measureWidth, MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(measureHeight, MeasureSpec.EXACTLY));
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        //hour
        if (mTextBg != null) {
            mTextBg.setBounds(0, mBgTop, mHourBgWidth, mBgTop + mBgHeight);
            mTextBg.draw(canvas);
        }

        mPaint.setColor(mTextColor);
        canvas.drawText(mHourText, mHourTextLeftOffset, mBaseLine, mPaint);

        //colon
        mPaint.setColor(mColonColor);
        final int colonLeft = mHourBgWidth + mColonPadding;
        canvas.drawRect(colonLeft, mColonTop, colonLeft + mColonSize, mColonTop + mColonSize, mPaint);

        final int colonTop2 = mColonTop + mColonSize + mColonPadding;
        canvas.drawRect(colonLeft, colonTop2, colonLeft + mColonSize, colonTop2 + mColonSize, mPaint);

        //minute text
        final int minuteLeft = mHourBgWidth + mColonSize + 2 * mColonPadding;
        if (mTextBg != null) {
            mTextBg.setBounds(minuteLeft, mBgTop, minuteLeft + mBgWidth, mBgTop + mBgHeight);
            mTextBg.draw(canvas);
        }

        mPaint.setColor(mTextColor);
        canvas.drawText(mMinuteText, minuteLeft + mTextLeftOffset, mBaseLine, mPaint);

        //colon
        mPaint.setColor(mColonColor);
        final int colonLeft2 = mHourBgWidth + mBgWidth + 2 * mColonPadding + mColonSize + mColonPadding;
        canvas.drawRect(colonLeft2, mColonTop, colonLeft2 + mColonSize, mColonTop + mColonSize, mPaint);

        canvas.drawRect(colonLeft2, colonTop2, colonLeft2 + mColonSize, colonTop2 + mColonSize, mPaint);

        //second text
        final int secondLeft = mHourBgWidth + mBgWidth + 2 * (mColonSize + 2 * mColonPadding);
        if (mTextBg != null) {
            mTextBg.setBounds(secondLeft, mBgTop, secondLeft + mBgWidth, mBgTop + mBgHeight);
            mTextBg.draw(canvas);
        }

        mPaint.setColor(mTextColor);
        canvas.drawText(mSecondText, secondLeft + mTextLeftOffset, mBaseLine, mPaint);
    }

    public void setOnCountDownListener(OnCountDownListener onCountDownListener) {
        this.mOnCountDownListener = onCountDownListener;
    }

    /**
     * 满足动态变色的需求
     */
    public void updateStyle(@DrawableRes int textBgRes, @ColorRes int textColorRes, @ColorRes int colonColorRes) {
        mTextBg = ContextCompat.getDrawable(getContext(), textBgRes);
        mTextColor = ContextCompat.getColor(getContext(), textColorRes);
        mColonColor = ContextCompat.getColor(getContext(), colonColorRes);
    }

    private Runnable mCountDownTask = () -> updateTime();

    /**
     * 更新当前时间
     */
    private void updateTime() {
        if (mCurCountTime < 0) {
            if (mOnCountDownListener != null) {
                mOnCountDownListener.onCountDownFinish();
            }
        } else {
            if (isDrawText) {
                int hour = mCurCountTime / 3600;
                int minute = (mCurCountTime % 3600) / 60;
                int second = mCurCountTime % 60;

                int lastHourTextLength = mHourText.length();
                mHourText = hour >= 10 ? String.valueOf(hour) : "0" + hour;
                mMinuteText = minute >= 10 ? String.valueOf(minute) : "0" + minute;
                mSecondText = second >= 10 ? String.valueOf(second) : "0" + second;

                if (lastHourTextLength != mHourText.length()) {
                    requestLayout();
                } else {
                    invalidate();
                }
            }

            mCurCountTime--;
            mHandler.postDelayed(mCountDownTask, 1000);
        }
    }

    /**
     * 开始倒计时
     *
     * @param totalSecond
     */
    public void startCountDown(int totalSecond) {
        stopCountDown();

        this.isDrawText = true;
        this.mCurCountTime = totalSecond;
        mHandler.post(mCountDownTask);
    }

    @Override
    protected void onVisibilityChanged(@NonNull View changedView, int visibility) {
        super.onVisibilityChanged(changedView, visibility);
        isDrawText = visibility == VISIBLE && getVisibility() == VISIBLE;
    }

    /**
     * 停止倒计时
     */
    public void stopCountDown() {
        mHandler.removeCallbacks(mCountDownTask);
    }

    public interface OnCountDownListener {
        void onCountDownFinish();
    }
}
